﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Common;
using System.IO;
using System.Linq;
using System.Text;

namespace KamLib
{
    public class HtmlReportWriter
    {
        public readonly TextWriter Writer;
        public HtmlReportWriter(TextWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException();
            Writer = writer;
        }
        public HtmlReportWriter(StringBuilder sb)
        {
            Writer = new StringWriter(sb);
        }


        #region HTML

        #region Simple Tags

        public HtmlReportWriter PAGE(string title = null, string criteria = null)
        {
            Writer.WriteLine("<html>\r\n<head>");
            if (title.IsFull())
                Writer.WriteLine("<title>" + title + "</title>");
            Writer.WriteLine(pageStyle);
            Writer.WriteLine("</head>\r\n<body bgcolor=white>");
            if (title.IsFull())
                Writer.WriteLine(@"<h1>{0}&nbsp; &nbsp; &nbsp;<small>{1}</small></h1>", title, DateTime.Now);
            if (criteria.IsFull())
                Writer.WriteLine(@"<small>Criteria: {0}</small><br><br>", criteria);

            return this;
        }

        public HtmlReportWriter _PAGE()
        {
            Writer.WriteLine("</body>\r\n</html>");
            return this;
        }

        public HtmlReportWriter H1(string text)
        {
            if (text.IsFull())
            {
                Writer.Write("<h1>");
                Writer.Write(text);
                Writer.WriteLine("</h1>");
            }
            return this;
        }
        public HtmlReportWriter H2(string text)
        {
            if (text.IsFull())
            {
                Writer.Write("<h2>");
                Writer.Write(text);
                Writer.WriteLine("</h2>");
            }
            return this;
        }
        public HtmlReportWriter H3(string text)
        {
            if (text.IsFull())
            {
                Writer.Write("<h3>");
                Writer.Write(text);
                Writer.WriteLine("</h3>");
            }
            return this;
        }

        public HtmlReportWriter BR()
        {
            Writer.WriteLine("<br/>");
            return this;
        }

        #endregion

        #region Constants

        public const string pageStyle = @"
<style type=""text/css"">
    body, table, h1, h2, h3, h4, h5, h6 { font-family: Arial; font-size: 10pt; }
    h1 { font-size: 16pt; }
    h2 { font-size: 14pt; font-weight:  }
    caption { font-size: 12pt; font-weight: bold; margin-bottom: 8px; }
    h3 { font-size: 12pt; pading: 0; margin-bottom: 4px; }
    h1 small { font-size: 0.8em; }
    big { font-size: 1.11em; } small { font-size: 0.9em; } th small { font-size: 0.8em; }
    .nobrd { border: none; }
    .nowrap { white-space: nowrap; }
    .calign { text-align: center !important; white-space: nowrap; }
    .ralign { text-align: right !important; white-space: nowrap; }
    .compact table { font-size: 7pt; }
    tr:hover td { background-color: #f0f0f0; }
    td ul { margin:0; padding: 0 0 0 16px; }
    table.brd { border: 1px solid silver; border-top: none; margin-bottom: 20px; }
    table.inner { border: none; margin: 0}
    th, thead td { background: #f0f0f0; font-size: 0.8em; padding:8px; vertical-align: middle; text-align: left; font-weight: bold; }
    th.desc { padding:2px; }
    th.desc2 { font-weight: normal; padding:2px; }
    .desc-header, .desc-header * { border: none } 
    .desc-header th { background: none; font-weight: normal; padding: 4px; text-align: right; vertical-align: top; white-space: nowrap; } 
    .desc-header td { font-weight: bold; padding: 4px; text-align: left; } 
    table.total { border: 1px solid silver; font-size:1.2em; margin-bottom: 20px; } 
    table.total th { background: none; border: none; font-weight: normal; padding: 4px 12px; text-align: right; vertical-align: top; white-space: nowrap; } 
    table.total td { font-weight: bold; padding: 4px 12px; text-align: left; } 
    td { padding: 3px 8px 3px 8px; vertical-align:top; }
    .compact th { font-size: 1em; }
    .compact td { padding: 2px; }
    tr.g1 td { border-top: 1px solid silver; } tr.g1 th { font-size: 1em; }
    tr.g2 td, th { border-top: 1px solid silver; background: #f0f0f0;}
    tr.g3 td { border-top: 1px solid silver; border-bottom: 1px solid silver; }
    table.brd tfoot td, table.brd-full tfoot td { background: #f0f0f0; } 
    table.brd-full { border-right: 1px solid silver; border-bottom: 1px solid silver; margin-bottom: 20px; }
    table.brd-full th, table.brd-full td {border-left: 1px solid silver; border-top: 1px solid silver; }
    table.light th { background: none; border: none; border-bottom: 1px solid silver; }
    table.light td { background: none; border: none; }
    .brd-l { border-left: 1px solid silver; } .brd-r { border-right: 1px solid silver; }
    .brd-t, tr.brd-t td, tr.brd-t th { border-top: 1px solid silver; } 
    .brd-t-light, tr.brd-t-light td, tr.brd-t-light th { border-top: 1px solid silver; }
    .brd-b, tr.brd-b td, tr.brd-b th { border-bottom: 1px solid silver; } 
    .brd-b-light, tr.brd-b-light td, tr.brd-b-light th { border-bottom: 1px solid silver; }
</style>
";

        #endregion

        #endregion


        #region Table

        public class TableColumn
        {
            public string Title;
            /// <summary>
            /// Он же dataIndex, для DbDataReader
            /// </summary>
            public int DataIndex;
            public string Align;
            public string VAlign;
            public bool Border;
            public int Span;
            public int Width;
        }

        public readonly List<TableColumn> TableColumns = new List<TableColumn>();
        public int ColIndex { get; protected set; }

        public HtmlReportWriter COL(string title = null, int dataIndex = -1, int width = -1, bool border = false, string align = null, string valign = null, int span = 1)
        {
            var prior = TableColumns.LastOrDefault();

            TableColumns.Add(new TableColumn
            {
                Title = title,
                DataIndex = dataIndex >= 0 ? dataIndex : prior != null ? prior.DataIndex + 1 : 0,
                Align = align,
                VAlign = valign,
                Border = border,
                Span = span,
                Width = width
            });

            Writer.Write("<col");
            if (align.IsFull())
                Writer.Write(" align=\"" + align + "\"");
            if (valign.IsFull())
                Writer.Write(" valign=\"" + valign + "\"");
            if (span > 1)
                Writer.Write(" span=\"" + span + "\"");
            if (width >= 0)
                Writer.Write(" width=\"" + width + "px\"");
            Writer.WriteLine(" />");
            return this;
        }
        public HtmlReportWriter COL_Int(string title = null, int dataIndex = -1, int width = -1, bool border = false, string align = "right", string valign = null, int span = 1)
        {
            return COL(title, dataIndex, width, border, align, valign, span);
        }
        public HtmlReportWriter COL_DateTime(string title = null, int dataIndex = -1, int width = -1, bool border = false, string align = "left", string valign = null, int span = 1)
        {
            return COL(title, dataIndex, width, border, align, valign, span);
        }

        #region Simple Tags

        public HtmlReportWriter TBL(string title = null, bool border = true, string cls = null)
        {
            TableColumns.Clear();
            Writer.Write(@"<table class=""");
            Writer.Write(cls ?? (border ? @"brd" : null));
            Writer.WriteLine(@""" border=0 cellpadding=0 cellspacing=0>");
            if (title.IsFull())
            {
                Writer.Write("<caption>");
                Writer.Write(title);
                Writer.WriteLine("</caption>");
            }
            return this;
        }
        public HtmlReportWriter _TBL()
        {
            Writer.WriteLine(tble);
            return this;
        }
        public HtmlReportWriter TR(bool border = false, string cls = null)
        {
            ColIndex = -1;
            Writer.Write("<tr");
            if (border || cls.IsFull())
            {
                Writer.Write(@" class=""");
                if (border)
                    Writer.Write("brd-b");
                if (cls.IsFull())
                    Writer.Write(" " + cls);
                Writer.Write(@"""");
            }
            Writer.WriteLine(">");
            return this;
        }
        public HtmlReportWriter _TR()
        {
            Writer.WriteLine("</tr>");
            return this;
        }

        public HtmlReportWriter TH(bool border = false, int colSpan = 1)
        {
            Writer.Write("<th");
            if (border)
                Writer.Write(@" class=""brd-r""");
            if (colSpan > 1)
                Writer.Write(@" colspan=""" + colSpan + @"""");
            Writer.Write(">");
            return this;
        }
        public HtmlReportWriter _TH()
        {
            Writer.Write("</th>");
            return this;
        }

        public HtmlReportWriter TD(bool border = false, int colSpan = 1)
        {
            Writer.Write("<td");
            if (border)
                Writer.Write(@" class=""brd-r""");
            if (colSpan > 1)
                Writer.Write(@" colspan=""" + colSpan + @"""");
            Writer.Write(">");
            return this;
        }
        public HtmlReportWriter _TD()
        {
            Writer.Write(tde);
            return this;
        }

        #endregion


        #region Composite Tags

        public HtmlReportWriter THEAD()
        {
            Writer.WriteLine("<thead>");
            TR(border: true);
            foreach (var col in TableColumns)
            {
                TH(col.Title, border: col.Border);
            }
            _TR();
            Writer.WriteLine("</thead>");
            return this;
        }

        public HtmlReportWriter TR(string text, bool border = false, string cls = null)
        {
            TR(border: border, cls: cls);

            var colCount = TableColumns.Count;
            if (colCount > 0)
            {
                var col = TableColumns[0];
                TD(text, border: col.Border, colSpan: colCount);
            }
            else
                TD(text);

            return _TR();
        }

        public HtmlReportWriter TR(IEnumerable cells)
        {
            TR();

            var colCount = TableColumns.Count;
            foreach (var cell in cells)
            {
                if (++ColIndex < colCount)
                {
                    var col = TableColumns[ColIndex];
                    TD(cell, border: col.Border);
                }
                else
                    TD(cell);
            }

            return _TR();
        }

        public HtmlReportWriter TR(params object[] cells)
        {
            return TR((IEnumerable)cells);
        }

        public HtmlReportWriter TR(DbDataReader reader)
        {
            TR();

            foreach (var col in TableColumns)
            {
                var text = reader[col.DataIndex];
                TD(text, border: col.Border);
            }

            return _TR();
        }

        public HtmlReportWriter TH(string text, bool border = false, int colSpan = 1)
        {
            TH(border: border, colSpan: colSpan);
            Writer.Write(ToText(text));
            return _TH();
        }

        public HtmlReportWriter TD(object text, bool border = false, int colSpan = 1)
        {
            TD(border: border, colSpan: colSpan);
            Writer.Write(ToText(text));
            _TD();
            return this;
        }

        #endregion


        #region Constants

        public const string tbl = @"<table class=""brd-full"" border=0 cellpadding=0 cellspacing=0>";
        public const string tbl_brd = @"<table class=""brd"" border=0 cellpadding=0 cellspacing=0>";
        public const string tbl_light = @"<table class=""light"" border=0 cellpadding=0 cellspacing=0>";
        public const string tbl_desc_header = @"<table class=""desc-header"" border=0 cellpadding=0 cellspacing=0>";
        public const string tbl_total = @"<table class=""total"" border=0 cellpadding=0 cellspacing=0>";
        public const string tble = @"</table>";

        public const string tr = @"<tr>";
        public const string tre = @"</tr>";
        public const string tr_brdt = @"<tr class=""brd-t"">";
        public const string tr_brdb = @"<tr class=""brd-b"">";

        public const string th = @"<th>";
        public const string th_brdl = @"<th class=""brd-l"">";
        public const string th_brdr = @"<th class=""brd-r"">";
        public const string thc = @"<th class=""calign"">";
        public const string thc_brdl = @"<th class=""calign brd-l"">";
        public const string thc_brdr = @"<th class=""calign brd-r"">";
        public const string thr = @"<th class=""ralign"">";
        public const string thr_brdl = @"<th class=""ralign brd-l"">";
        public const string thr_brdr = @"<th class=""ralign brd-r"">";
        public const string the = @"</th>";

        public const string td = @"<td>";
        public const string td_brdl = @"<td class=""brd-l"">";
        public const string td_brdr = @"<td class=""brd-r"">";
        public const string tdc = @"<td class=""calign"">";
        public const string tdc_brdl = @"<td class=""calign brd-l"">";
        public const string tdc_brdr = @"<td class=""calign brd-r"">";
        public const string tdr = @"<td class=""ralign"">";
        public const string tdr_brdl = @"<td class=""ralign brd-l"">";
        public const string tdr_brdr = @"<td class=""ralign brd-r"">";
        public const string tde = @"</td>";

        public const string td_nowrap = @"<td class=""nowrap"">";

        #endregion

        #endregion


        #region Utils

        public string ToText(string value)
        {
            return value.IfNull("&nbsp;");
        }
        public string ToText(object value)
        {
            return value != null ? value.ToString().IfNull("&nbsp;") : "&nbsp;";
        }

        #endregion
    }
}
